package com.gitee.l0km.aocache;

import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Objects;

import com.gitee.l0km.aocache.config.CacheConfigSupplier;

/**
 * <p>MemberKey类用于唯一标识一个成员（如方法、字段等）及其关联的目标对象。</p>
 * <p>该类封装了成员信息和目标对象，同时支持可选的{@link CacheConfigSupplier}实例。</p>
 * <p>它重写了hashCode、equals和toString方法，确保在集合中正确使用和调试时的可读性。</p>
 * 
 * <p>主要特性包括：</p>
 * <ul>
 *   <li>对于静态成员，目标对象强制为null，避免比较时出现问题。</li>
 *   <li>提供了静态工厂方法of来创建MemberKey实例。</li>
 *   <li>{@link CacheConfigSupplier}实例不参与hashCode和equals计算。</li>
 * </ul>
 */
public class MemberKey {
	final Member member;
	final Object target;
	/** 
	 * 切入点(JoinPoint)缓存配置定义提供的{@link CacheConfigSupplier}实例<br>
	 * 不参与hash,equals,toString。 
	 */
	final CacheConfigSupplier jpConfigSupplier;
	/** 
	 * 外部输入的{@link CacheConfigSupplier}实例<br>
	 * 不参与hash,equals,toString。 
	 */
	final CacheConfigSupplier inputSupplier;
	private MemberKey(Member member, Object target) {
		this(member, target, null, null);
	}
	private MemberKey(Member member, Object target, CacheConfigSupplier jpConfigSupplier, CacheConfigSupplier inputSupplier) {
		this.member = Objects.requireNonNull(member,"member can not be null");
        if (Modifier.isStatic(member.getModifiers())) {
            this.target = null;// 静态成员对象的target强制为null，避免在对象比较(equals)时出现问题
        } else {
            this.target = target;
        }
        this.jpConfigSupplier = jpConfigSupplier;
        this.inputSupplier = inputSupplier;
	}
    private MemberKey(Member member) {
        this(member, null);
    }
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((member == null) ? 0 : member.hashCode());
		/**
		 * NOTE: 这里特意调用 System.identityHashCode(target)，获取 target 的哈希值
		 * 确保每个 MemberKey 对象的 target 都是同一个对象。
		 */
		result = prime * result + (System.identityHashCode(target));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof MemberKey)) {
			return false;
		}
		MemberKey other = (MemberKey) obj;
		/** NOTE: target 特意使用 == 比较，确保每个 MemberKey 对象的 target 都是同一个对象。 */
		return target == other.target && Objects.equals(member, other.member);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("MemberKey [");
		if (member != null) {
			builder.append("member=").append(member).append(", ");
		}
		if (target != null) {
			/** target只输出输出 target 的 class name 和 hashcode */
			builder.append("target=").append(target.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(target)));
		}
		builder.append("]");
		return builder.toString();
	}
    /**
     * 创建一个新的 MemberKey 实例。
     * <p>
     * 如果提供的 target 为 null，将调用单参数构造函数创建一个静态成员的 MemberKey。
     * 否则，将调用双参数构造函数创建一个包含目标对象的 MemberKey。
     * </p>
     * 
     * @param member 要关联的成员，不能为 null。
     * @param target 要关联的目标对象，如果成员是静态的，则该参数将被忽略。
     * @return 一个新的 MemberKey 实例。
     */
    public static MemberKey of(Member member, Object target) {
        return of(member, target, null, null);
    }

    /**
     * 创建一个新的 MemberKey 实例，包含成员、目标对象以及可选的切入点缓存配置和外部输入配置。
     * <p>
     * 此方法允许你指定一个成员、目标对象，以及两个可选的{@link CacheConfigSupplier}实例，
     * 分别用于切入点缓存配置和外部输入配置。
     * </p>
     * <p>
     * 如果成员是静态的，目标对象将被忽略，并且在构造过程中会被设置为 null。
     * </p>
     * 
     * @param member 要关联的成员，不能为 null。
     * @param target 要关联的目标对象，如果成员是静态的，则该参数将被忽略。
     * @param jpConfigSupplier 切入点缓存配置提供的{@link CacheConfigSupplier}实例，可为 null。
     * @param inputSupplier 外部输入的{@link CacheConfigSupplier}实例，可为 null。
     * @return 一个新的 MemberKey 实例。
     */
	public static MemberKey of(Member member, Object target, CacheConfigSupplier jpConfigSupplier,
			CacheConfigSupplier inputSupplier) {
		return new MemberKey(member, target, jpConfigSupplier, inputSupplier);
	}
}
